/***************************************************************************
 *   Copyright (C) 2009 by Zheng Yonglei
 *   zhengyonglei@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <QMenu>

#include "MessageBox.h"
#include "LoginDialog.h"
#include "ExportDataDialog.h"
#include "ImportDataDialog.h"
#include "AboutThisApplication.h"
#include "SelectListDialog.h"
#include "ReciteGREWords.h"
#include "DictMaker.h"
#include "Logger.h"

ReciteGREWords::ReciteGREWords(QWidget *parent)
    : QMainWindow(parent),
    mTime(QTime(0,0,0))
{
	ui.setupUi(this);

	//set menu
	mLanguageChinese = new QAction("Chinese", this);
	mLanguageChinese->setCheckable(true);
	mLanguageChinese->setChecked(true);
	mLanguageEnglish = new QAction("English", this);
	mLanguageEnglish->setCheckable(true);
	QMenu* languageMenu = new QMenu(tr("Language"), this);
	this->menuBar()->addMenu(languageMenu);
	languageMenu->addAction(mLanguageChinese);
	languageMenu->addAction(mLanguageEnglish);
	mLanguageActionGroup = new QActionGroup(this);
	mLanguageActionGroup->addAction(mLanguageChinese);
	mLanguageActionGroup->addAction(mLanguageEnglish);
	mLanguageActionGroup->setExclusive(true);
	if (OPT.language == mLanguageChinese->text())
		mLanguageChinese->setChecked(true);
	else if (OPT.language == mLanguageEnglish->text())
		mLanguageEnglish->setChecked(true);
	else
		mLanguageEnglish->setChecked(true);
	QObject::connect(mLanguageActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(languageChanged(QAction*)));

	ui.actionSettings->setIcon(QIcon(":/pixmaps/configure.png"));
	ui.actionAbout->setText(tr("About ReciteGREWords"));
	ui.actionAbout->setIcon(QIcon(":/pixmaps/dialog-information.png"));
	QObject::connect(ui.actionSettings, SIGNAL(triggered()), this, SLOT(showSettingDialog()));
	QObject::connect(ui.actionAbout, SIGNAL(triggered()), this, SLOT(showAboutThisApplication()));

	QShortcut* spaceBarShortcut = new QShortcut(QKeySequence(Qt::Key_Space),  this);
	QObject::connect(spaceBarShortcut,SIGNAL(activated()),this,SLOT(spaceBarPressed()));

	//set manu bar
	mImportData = new QAction(QIcon(":/pixmaps/db_comit-256.png"), tr("Import data"), this);
	mImportData->setStatusTip(tr("Import data"));
	ui.menuTools->addAction(mImportData);
	connect(mImportData, SIGNAL(triggered()), this, SLOT(showImportDataDialog()));

	mExportData = new QAction(QIcon(":/pixmaps/db_update-256.png"), tr("Export data"), this);
	mExportData->setStatusTip(tr("Export data"));
	ui.menuTools->addAction(mExportData);
	connect(mExportData, SIGNAL(triggered()), this, SLOT(showExportDataDialog()));

	mOpenDictMakerAct = new QAction(QIcon(":/pixmaps/warehause.png"), tr("Dictionary Maker"), this);
	mOpenDictMakerAct->setStatusTip(tr("Open Dictionary Maker"));
	ui.menuTools->addAction(mOpenDictMakerAct);
	connect(mOpenDictMakerAct, SIGNAL(triggered()), this, SLOT(showDictMakerDialog()));

	//set tool bar
	mOpenListAct = new QAction(QIcon(":/pixmaps/fileopen-256.png"), tr("Open List"), this);
	mOpenListAct->setStatusTip(tr("Open a list."));
	connect(mOpenListAct, SIGNAL(triggered()), this, SLOT(showSelectListDialog()));

	mOpenAnalysisDialogAct = new QAction(QIcon(":/pixmaps/kchart.png"), tr("Open Testing Analysis Dialog"), this);
	mOpenAnalysisDialogAct->setStatusTip(tr("Open Testing Analysis Dialog"));
	connect(mOpenAnalysisDialogAct, SIGNAL(triggered()), this, SLOT(showAnalysisDialog()));

	mResumeAct = new QAction(QIcon(":/pixmaps/forward-256.png"), tr("Resume Last Task"), this);
	mResumeAct->setStatusTip(tr("Resume last task."));
	connect(mResumeAct, SIGNAL(triggered()), this, SLOT(resume()));

	mStartAct = new QAction(QIcon(":/pixmaps/player_play-256.png"), tr("Start"), this);
	mStartAct->setStatusTip(tr("Start current task."));
	connect(mStartAct, SIGNAL(triggered()), this, SLOT(startButtonPushed()));

	mPauseAct = new QAction(QIcon(":/pixmaps/player_pause-256.png"), tr("Pause"), this);
	mPauseAct->setStatusTip(tr("Pause current task."));
	connect(mPauseAct, SIGNAL(triggered()), this, SLOT(pauseButtonPushed()));

	mFinishedCurTaskAct = new QAction(QIcon(":/pixmaps/player_stop-256.png"), tr("Finish"), this);
	mFinishedCurTaskAct->setStatusTip(tr("Finish Current Task."));
	connect(mFinishedCurTaskAct, SIGNAL(triggered()), this, SLOT(finishCurTask()));

	mZoomIn = new QAction(QIcon(":/pixmaps/viewmag+-256.png"), tr("Zoom In"), this);
	mZoomIn->setStatusTip(tr("Enlarge Font"));
	connect(mZoomIn, SIGNAL(triggered()), this, SLOT(zoomIn()));

	mZoomOut = new QAction(QIcon(":/pixmaps/viewmag--256.png"), tr("Zoom Out"), this);
	mZoomOut->setStatusTip(tr("Reduce Font"));
	connect(mZoomOut, SIGNAL(triggered()), this, SLOT(zoomOut()));

	mShowLoginDialog = new QAction(QIcon(":/pixmaps/identity-256.png"), tr("Open Login Dialog"), this);
	mShowLoginDialog->setStatusTip(tr("Open login dialog"));
	connect(mShowLoginDialog, SIGNAL(triggered()), this, SLOT(showLoginDialog()));

	mExitApp = new QAction(QIcon(":/pixmaps/application-exit.png"), tr("Exit"), this);
	mExitApp->setStatusTip(tr("Exit ReciteGREWords"));
	connect(mExitApp, SIGNAL(triggered()), this, SLOT(exitApp()));

	mShowTrainer = new QAction(QIcon(":/pixmaps/ktip.png"), tr("Show ANN"), this);
	mShowTrainer->setStatusTip(tr("Manage ANN"));
	connect(mShowTrainer, SIGNAL(triggered()), this, SLOT(showANN()));

	ui.toolBar->addAction(mResumeAct);
	ui.toolBar->addSeparator();
	ui.toolBar->addAction(mStartAct);
	ui.toolBar->addAction(mPauseAct);
	ui.toolBar->addAction(mFinishedCurTaskAct);
	ui.toolBar->addSeparator();

	ui.toolBar->addAction(mZoomIn);
	ui.toolBar->addAction(mZoomOut);

	ui.toolBar->addSeparator();
	ui.toolBar->addAction(mShowLoginDialog);
	ui.toolBar->addAction(mOpenAnalysisDialogAct);
	ui.toolBar->addAction(mOpenListAct);

	ui.toolBar->addSeparator();
	ui.toolBar->addAction(mShowTrainer);

	QObject::connect(&mTaskTimer, SIGNAL(timeout()), this, SLOT(updateTimeElapsedDisplay()));
	mTimeElapsedEditor = new QTimeEdit(this);
	mTimeElapsedEditor->setDisplayFormat(QString("h:mm:ss"));
	mTimeElapsedEditor->setTime(QTime(0,0,0));
	mTimeElapsedEditor->setReadOnly(true);
	mTimeElapsedEditor->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
	ui.toolBar->addSeparator();
	ui.toolBar->addWidget(mTimeElapsedEditor);

	mMainBulletin = new QTextEdit(this);
	mMainBulletin->setReadOnly(true);
	mMainBulletin->setMaximumHeight(35);
	ui.toolBar->addWidget(mMainBulletin);

	ui.toolBar->addSeparator();
	ui.toolBar->addAction(mExitApp);

	mTestWidget = new TestWidget(this);
	mTestWidget->hide();
	QObject::connect(	mTestWidget, SIGNAL(updateMainBulletin()),
								this, SLOT(updateMainBulletin()));
	QObject::connect(	mTestWidget, SIGNAL(curTestFinished()),
								this, SLOT(finishCurTask()));
	QObject::connect(	mTestWidget, SIGNAL(showSelectListDialog()),
								this, SLOT(showSelectListDialog()));
	QObject::connect(	mTestWidget, SIGNAL(showAnalysisDialog()),
								this, SLOT(showAnalysisDialog()));

	mLinearBrowser = new LinearBrowser(this);
	mLinearBrowser->hide();

	mDictionary = new Dictionary(this);
	mDictionary->hide();

	QGridLayout* centralGrid = new QGridLayout(ui.centralwidget);
	centralGrid->setContentsMargins(0, 0, 0, 0);
	centralGrid->addWidget(mTestWidget, 0, 0);
	centralGrid->addWidget(mLinearBrowser, 0, 0);
	centralGrid->addWidget(mDictionary, 0, 0);

	mOpenListAct->setEnabled(false);
	mOpenAnalysisDialogAct->setEnabled(false);
	mResumeAct->setEnabled(false);
	mStartAct->setEnabled(false);
	mPauseAct->setEnabled(false);
	mFinishedCurTaskAct->setEnabled(false);
	//mZoomIn->setEnabled(false);
	//mZoomOut->setEnabled(false);
	mShowTrainer->setEnabled(false);
}

ReciteGREWords::~ReciteGREWords()
{
	OPT.mainWinGeo = this->geometry();
}

void ReciteGREWords::show()
{
	if (OPT.mainWindowStatus == Qt::WindowMaximized)
		QWidget::showMaximized();
	else
	{
		this->setGeometry(OPT.mainWinGeo);
		QWidget::show();
	}

	setProgramFont();
}

void ReciteGREWords::languageChanged(QAction* action)
{
	if (action->text() != OPT.language)
	{
		OPT.language = action->text();
		QString message=QString("Please restart the application to have language changed.");
		QMessageBox msgBox;
		msgBox.setWindowTitle("Language changed");
		msgBox.setText(message);
		msgBox.exec();
	}
}

void ReciteGREWords::login()
{
	mOpenListAct->setEnabled(true);
	mOpenAnalysisDialogAct->setEnabled(true);
	mResumeAct->setEnabled(true);
	mPauseAct->setEnabled(true);
	mFinishedCurTaskAct->setEnabled(true);
	mShowTrainer->setEnabled(true);

	QString curTitle = windowTitle();
	if (curTitle.contains("--"))
		curTitle = curTitle.left(curTitle.indexOf("--"));
	setWindowTitle(curTitle + "--" + DB.curUsr);

	if (OPT.autoStartTrainer)
		mTrainer.startTraining();
}

void ReciteGREWords::logout()
{
	if (!DB.curUsr.isEmpty())
	{
		finishCurTask();
		DB.closeDB(DB.curUsr);
		DB.curUsr.clear();

		mOpenListAct->setEnabled(false);
		mOpenAnalysisDialogAct->setEnabled(false);
		mResumeAct->setEnabled(false);
		mPauseAct->setEnabled(false);
		mFinishedCurTaskAct->setEnabled(false);
		mShowTrainer->setEnabled(true);

		QString curTitle = windowTitle();
		if (curTitle.contains("--"))
			curTitle = curTitle.left(curTitle.indexOf("--"));
		setWindowTitle(curTitle);
	}

	mTrainer.stopTraining();
}

void ReciteGREWords::showSettingDialog()
{
	float sizeRate = 0.6f;
	SettingsDialog dialog;
	dialog.setGeometry(OPT.scaleGeometry(OPT.mainWinGeo, sizeRate, sizeRate));
	dialog.exec();
	setProgramFont();
	this->raise();
	this->activateWindow();
}

void ReciteGREWords::setProgramFont()
{
	this->setFont(OPT.programFont);

	mTestWidget->setFont(OPT.programFont);
	mTestWidget->setDisplayFont(OPT.wordBrowserFont);

	mLinearBrowser->setFont(OPT.programFont);
	mLinearBrowser->setDisplayFont(OPT.wordBrowserFont);

	mDictionary->setDisplayFont(OPT.wordBrowserFont);

	mImportData->setFont(OPT.programFont);
	mExportData->setFont(OPT.programFont);
}

void ReciteGREWords::showAboutThisApplication()
{
	AboutThisApplication dialog;
	float sizeRate = 0.5f;
	dialog.setGeometry(OPT.scaleGeometry(OPT.mainWinGeo, sizeRate, sizeRate));
	dialog.setFont(OPT.programFont);
	dialog.exec();
}

void ReciteGREWords::showSelectListDialog()
{
	float sizeRate = 0.8f;
	SelectListDialog dialog;
	dialog.setGeometry(OPT.scaleGeometry(OPT.mainWinGeo, sizeRate, sizeRate));
	dialog.setFont(OPT.programFont);

	int val = dialog.exec();
	LOG<<"return value="<<val<<endl;
	switch (val)
	{
	case TT_Test:
		finishCurTask();
		startMemorizationTest();
		break;
	case TT_Browse:
		finishCurTask();
		startWordBrowse();
		break;
	case TT_None:
		break;
	}

	this->raise();
	this->activateWindow();
}

void ReciteGREWords::showAnalysisDialog()
{
	float sizeRate = 0.9f;
	TestResultAnalysisDialog dialog;
	dialog.setGeometry(OPT.scaleGeometry(OPT.mainWinGeo, sizeRate, sizeRate));
	dialog.setFont(OPT.programFont);
	int val = dialog.exec();
	LOG<<"return value="<<val<<endl;
	switch (val)
	{
	case TT_Test:
		finishCurTask();
		startMemorizationTest();
		break;
	case TT_Browse:
		finishCurTask();
		startWordBrowse();
		break;
	case TT_None:
		break;
	}

	this->raise();
	this->activateWindow();
}

void ReciteGREWords::showExportDataDialog()
{
	ExportDataDialog exportDataDialog;
	float widthSizeRate = 0.5f;
	float heightSizeRate = 0.8f;
	exportDataDialog.setGeometry(OPT.scaleGeometry(OPT.mainWinGeo, widthSizeRate, heightSizeRate));
	exportDataDialog.setFont(OPT.programFont);
	exportDataDialog.exec();
	this->raise();
	this->activateWindow();
}

void ReciteGREWords::showImportDataDialog()
{
	float widthSizeRate = 0.5f;
	float heightSizeRate = 0.8f;
	ImportDataDialog importDataDialog;
	importDataDialog.setGeometry(OPT.scaleGeometry(OPT.mainWinGeo, widthSizeRate, heightSizeRate));
	importDataDialog.setFont(OPT.programFont);
	importDataDialog.exec();
	this->raise();
	this->activateWindow();
}

void ReciteGREWords::showANN()
{
	float sizeRate = 0.9f;
	mTrainer.setGeometry(OPT.scaleGeometry(OPT.mainWinGeo, sizeRate, sizeRate));
	mTrainer.show();
}

void ReciteGREWords::showDictMakerDialog()
{
	float sizeRate = 0.6f;
	//LOG<<"sizeRate="<<sizeRate<<endl;
	DictMaker dictMaker;
	dictMaker.setGeometry(OPT.scaleGeometry(OPT.mainWinGeo, sizeRate, sizeRate));
	dictMaker.setFont(OPT.programFont);
	dictMaker.exec();
	this->raise();
	this->activateWindow();
}


bool ReciteGREWords::startMemorizationTest()
{
	//finishCurTask();
	mTestWidget->setVisible(true);
	if (!mTestWidget->prepareToTest())
	{
		LOG<<"Fail to start Memorization Test"<<endl;
		return false;
	}
	else
	{
		mResumeAct->setEnabled(false);
		mMainBulletin->clear();

		mDictionary->hide();
		mLinearBrowser->hide();
		mTestWidget->show();
	}

	mTaskTimer.start(1000);
	mTime = mTestWidget->testManager().testElapseTime;

	updateMainBulletin();
	return true;
}

bool ReciteGREWords::startWordBrowse()
{
	LOG<<"Prepare to start word browser."<<endl;
	mMainBulletin->clear();
	mLinearBrowser->show();
	mLinearBrowser->initBrowseTask();
	return true;
}

void ReciteGREWords::pauseButtonPushed()
{
	centralWidget()->setEnabled(false);
	mOpenListAct->setEnabled(false);
	mOpenAnalysisDialogAct->setEnabled(false);
	mStartAct->setEnabled(true);
	mPauseAct->setEnabled(false);
	mExitApp->setEnabled(true);
	OPT.isPaused = true;
}

void ReciteGREWords::startButtonPushed()
{
	centralWidget()->setEnabled(true);
	mOpenListAct->setEnabled(true);
	mOpenAnalysisDialogAct->setEnabled(true);
	mStartAct->setEnabled(false);
	mPauseAct->setEnabled(true);
	mExitApp->setEnabled(true);
	OPT.isPaused = false;
}

void ReciteGREWords::spaceBarPressed()
{
	if (OPT.isPaused)
		mStartAct->trigger();
	else
		mPauseAct->trigger();
}

void ReciteGREWords::finishCurTask()
{
	mTaskTimer.stop();
	if (mTestWidget->isVisible())
	{
		mTestWidget->hide();
		mTestWidget->testManager().finishCurTask();
		LOG<<"Last task is memorizing test."<<endl;
	}
	else if (mLinearBrowser->isVisible())
	{
		mLinearBrowser->hide();
		mLinearBrowser->wordManager().finishCurTask();
		LOG<<"Last task is browsing the words."<<endl;
	}
	else if (mDictionary->isVisible())
	{
		mDictionary->hide();
	}
	else
		LOG<<"NO task to finish."<<endl;

	LOG<<"Current task finished."<<endl;
}

void ReciteGREWords::updateTimeElapsedDisplay()
{
	mTimeElapsedEditor->setTime(mTime);
	if(!mStartAct->isEnabled())
	{
		mTime = mTime.addSecs(1);
		mTestWidget->testManager().testElapseTime = mTime;
	}
}

void ReciteGREWords::updateMainBulletin()
{
	mMainBulletin->clear();
	QString ActiveWordCount = QString(
			"<FONT COLOR='blue'>Active: <B>%1. </B></FONT>"
			).arg(mTestWidget->testManager().getActivatedWordCount());
	QString TestingWordCount = QString(
			"<FONT COLOR='#330066'>Testing: <B>%1. </B></FONT>"
			).arg(mTestWidget->testManager().getTestingWordCount());
	QString FinishedWordCount = QString(
			"<FONT COLOR='green'>Finished: <B>%1. </B></FONT>"
			).arg(mTestWidget->testManager().getActivatedWordTotalFinishedCount());
	QString UnhitRevWordCount = QString(
			"<FONT COLOR='red'>To-Review: <B>%1. </B></FONT>"
			).arg(mTestWidget->testManager().getTestFinishedFirstCount());

	mMainBulletin->insertHtml(ActiveWordCount);
	mMainBulletin->insertHtml(TestingWordCount);
	mMainBulletin->insertHtml(FinishedWordCount);
	mMainBulletin->insertHtml(UnhitRevWordCount);
}


void ReciteGREWords::exitApp()
{
	QCoreApplication::quit();
}

void ReciteGREWords::resume()
{
	finishCurTask();
	mTestWidget->testManager().resumeTest = true;
	if (!startMemorizationTest())
	{
		QString message= tr("Cannot resume the last test. Please start a new one. ");
		MessageBox::showWarning(QMessageBox::Warning,QString("Warning!"),message,12,this);
	}
}

void ReciteGREWords::zoomIn()
{
	int fontSize = OPT.wordBrowserFont.pointSize();
	fontSize++;
	OPT.wordBrowserFont.setPointSize(fontSize);
	mTestWidget->setDisplayFont(OPT.wordBrowserFont);
	mLinearBrowser->setDisplayFont(OPT.wordBrowserFont);
	mDictionary->setDisplayFont(OPT.wordBrowserFont);
}

void ReciteGREWords::zoomOut()
{
	int fontSize = OPT.wordBrowserFont.pointSize();
	fontSize--;
	OPT.wordBrowserFont.setPointSize(fontSize);
	mTestWidget->setDisplayFont(OPT.wordBrowserFont);
	mLinearBrowser->setDisplayFont(OPT.wordBrowserFont);
	mDictionary->setDisplayFont(OPT.wordBrowserFont);
}

void ReciteGREWords::showLoginDialog()
{
	float sizeRate = 0.5f;
	LoginDialog loginDialog;
	loginDialog.setGeometry(OPT.scaleGeometry(OPT.mainWinGeo, sizeRate, sizeRate));
	loginDialog.setFont(OPT.programFont);

	int val = loginDialog.exec();
	if (val == LT_Success)
		login();
	else if (val == LT_Dictionary)
		dictMode();
	else if (!OPT.hasLogined && !DB.curUsr.isEmpty())
		logout();
	else
		LOG<<"Unexpected return value"<<endl;

	this->raise();
	this->activateWindow();
}

void ReciteGREWords::dictMode()
{
	finishCurTask();
	mDictionary->show();
}

